package com.sand.service.Impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sand.Exception.SandException;
import com.sand.SignUtils;
import com.sand.dto.Owner.*;
import com.sand.dto.Select.UserSelect;
import com.sand.entity.buy.detail;
import com.sand.entity.shopping.shopping;
import com.sand.entity.user.User;
import com.sand.feign.OwnerFeign;
import com.sand.feign.ShoppingFeign;
import com.sand.feign.UserFeign;
import com.sand.mapper.DetailMapper;
import com.sand.result.AppHttpCodeEnum;
import com.sand.result.ResponseResult;
import com.sand.service.DetailService;
import com.sand.service.SignService;
import com.sand.user.UserType;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

@Service
public class DetailServiceImpl extends ServiceImpl<DetailMapper, detail> implements DetailService {

    @Autowired
    private UserFeign userFeign;

    @Autowired
    private ShoppingFeign shoppingFeign;

    @Autowired
    private SignService signService;

    @Autowired
    private OwnerFeign ownerFeign;

    /**
     * 客户预购和修改
     *
     * @param add
     */
    @Override
    @Transactional
    public String addOrupdate(DetailAdd add) {

        //参数校验
        chanshu(add);

        //操作人校验
        User user = getUser(add.getUserid());

        //商品校验
        ResponseResult<List<shopping>> shoppingList = getShoppingList(add);

        if (shoppingList == null) {
            throw new SandException(AppHttpCodeEnum.PARAM_INVALID, "添加的商品存在错误");
        }

        if (shoppingList.getData() == null) {
            throw new SandException(AppHttpCodeEnum.PARAM_INVALID, shoppingList.msg);
        }

        //判断是修改还是新增
        if (add.getId() == null) {

            //生成标记
            String sign = SignUtils.sign(user.getPhone());

            //计算金额
            Integer money = getMoney(shoppingList.getData(), add.getList());

            detail detail = new detail();

            //设置参数
            detail.setUserid(user.getId());
            detail.setBring(0); //对于新增和修改来说:默认设置不纳入方案表
            detail.setSign(sign);
            detail.setMoney(money);

            //添加到明细表
            save(detail);

            //添加到标记表
            Integer i = signService.addAll(new signAddAll(sign, add.getList()));

            if (i != 1) {
                throw new SandException(AppHttpCodeEnum.PARAM_INVALID, "添加到标识表失败");
            }

            return "添加预购成功";


        }

        //判断id是否存在
        detail detail = getById(add.getId());

        if (detail == null) {
            throw new SandException(AppHttpCodeEnum.PARAM_INVALID, "传入的修改的id有误");
        }

        if (detail.getBring() == 1) {
            throw new SandException(AppHttpCodeEnum.PARAM_INVALID, "该预购已经纳入方案无法修改");
        }

        //删除标记对应的商品
        Integer i = signService.delete(detail.getSign());

        //修改金额
        detail.setMoney(getMoney(shoppingList.getData(), add.getList()));

        //修改明细表
        updateById(detail);

        //新增标记表
        Integer j = signService.addAll(new signAddAll(detail.getSign(), add.getList()));

        if (j != 1) {
            throw new SandException(AppHttpCodeEnum.PARAM_INVALID, "添加到标识表失败");
        }

        return "修改方案预购成功";
    }


    /**
     * 客户根据标记查询预购
     *
     * @param sign
     * @return
     */
    @Override
    public DetailDto select(String sign) {
        //判断是否标记存在
        LambdaQueryWrapper<detail> wrapper = new LambdaQueryWrapper<detail>().eq(detail::getSign, sign);

        detail detail = getOne(wrapper);

        if (detail == null) {
            return null;
        }

        //根据标记获取对应的标记表
        List<signSelect> select = signService.select(sign);

        //根据id
        DetailDto detailDto = new DetailDto();

        BeanUtils.copyProperties(detail, detailDto);

        detailDto.setList(select);

        return detailDto;
    }

    /**
     * 客户删除预购
     *
     * @param delete
     */
    @Override
    @Transactional
    public Integer delete(DetailDelete delete) {
        if (delete.getUserid() == null) {
            throw new SandException(AppHttpCodeEnum.PARAM_INVALID, "未传入操作人");
        }

        if (delete.getSignid() == null) {
            throw new SandException(AppHttpCodeEnum.PARAM_INVALID, "未传入要修改signid");
        }

        //操作人判断
        getUser(delete.getUserid());

        detail detail = getById(delete.getSignid());

        if (detail == null) {
            throw new SandException(AppHttpCodeEnum.PARAM_INVALID, "传入的signid有误无法查询到数据");
        }

        if (!Objects.equals(detail.getUserid(), delete.getUserid())) {
            throw new SandException(AppHttpCodeEnum.PARAM_INVALID, "客户只能删除自己的预购");
        }

        //删除明细表
        removeById(detail);

        //根据标记删除标记表
        signService.delete(detail.getSign());

        return 1;
    }


    /**
     * 查看客户对应的所有预购
     *
     * @param userid
     */
    @Override
    public List<DetailDto> selectAll(Integer userid) {

        //操作人判断
        getUser(userid);

        //获取操作人的所有标记
        LambdaQueryWrapper<detail> wrapper = new LambdaQueryWrapper<detail>().eq(detail::getUserid, userid);

        //获取到所有关于这个用户的明细记录
        List<detail> list = list(wrapper);

        //判断该用户是否添加了预购
        if (list == null || list.isEmpty()) {
            return null;
        }

        //用于存放返回的数据
        ArrayList<DetailDto> dtos = new ArrayList<>();

        for (int i = 0; i < list.size(); i++) {
            //获取明细表
            detail detail = list.get(i);

            //获取标记
            String sign = detail.getSign();

            //根据标记获取数据
            List<signSelect> select = signService.select(sign);

            //构件DetailDto
            DetailDto detailDto = new DetailDto();

            //复制属性
            BeanUtils.copyProperties(detail, detailDto);

            //设置标记的商品
            detailDto.setList(select);

            //添加到返回的集合
            dtos.add(detailDto);
        }

        return dtos;
    }

    /**
     * 添加预购到方案
     *
     * @param detailId
     */
    @Override
    @Transactional
    public String addScheme(Integer detailId) {

        if (detailId == null){
            throw new SandException(AppHttpCodeEnum.PARAM_INVALID,"没有传入要添加到方案的明细表id");
        }

        detail detail = getById(detailId);

        if (detail == null){
            throw new SandException(AppHttpCodeEnum.PARAM_INVALID,"传入的明细表id有误");
        }

        //修改预购状态
        detail.setBring(1);

        updateById(detail);

        return "确认预购成功" ;
    }


    /**
     * 判断操作人是否是客户
     * @param userid
     * @return
     */
    private User getUser(Integer userid) {
        User user = userFeign.inquire(new UserSelect(userid, null)).getData();

        if (user == null) {
            throw new SandException(AppHttpCodeEnum.PARAM_INVALID, "当前用户不存在");
        }

        if (user.getType() != UserType.OWNER) {
            throw new SandException(AppHttpCodeEnum.PARAM_INVALID, "当前用户不是客户");
        }
        return user;
    }

    /**
     * 根据商品ids获取所有商品
     * @param add
     * @return
     */
    private ResponseResult<List<shopping>> getShoppingList(DetailAdd add) {

        List<SignAdd> adds = add.getList();

        if (adds.isEmpty()) {
            return null;
        }

        //存放所有商品的id
        Integer[] ints = new Integer[adds.size()];

        for (int i = 0; i < adds.size(); i++) {
            SignAdd signAdd = adds.get(i);
            ints[i] = signAdd.getShoppingid();
        }
        //根据ids查询所有商品
        return shoppingFeign.select(ints);

    }

    /**
     * 新增参数校验
     * @param add
     */
    private void chanshu(DetailAdd add) {
        if (add.getUserid() == null) {
            throw new SandException(AppHttpCodeEnum.PARAM_INVALID, "未传入用户");
        }

        if (add.getList() == null) {
            throw new SandException(AppHttpCodeEnum.PARAM_INVALID, "未传入要添加的商品");
        }

    }


    /**
     * 计算金额
     */
    private static Integer getMoney(List<shopping> list, List<SignAdd> addList) {

        if (list == null) {
            return 0;
        }

        int amount = 0;

        for (int i = 0; i < addList.size(); i++) {
            for (int j = 0; j < list.size(); j++) {
                if (Objects.equals(addList.get(i).getShoppingid(), list.get(j).getId())) {
                    amount += list.get(i).getPrice() * addList.get(i).getAmount();
                }
            }
        }

        return amount;
    }


}
